home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
src
/
haeberli
/
libgutil
/
follow.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
11KB
|
534 lines
/*
* Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
/*
* follow -
* Sweep a template along a curve.
*
* Paul Haeberli - 1990
*/
#include "stdio.h"
#include "math.h"
#include "vect.h"
#include "sgiobj.h"
#include "setjmp.h"
#include "triangulate.h"
static newsegment();
static normsegs();
static getcornervect();
static transtemp();
static putobjvert();
float frand();
sgiobj *follow();
sgiobj *getfaces();
#define MAXPATH 1000
#define MAXTEMP 1000
#define EPSILON 0.00001
typedef struct segment {
int prev, next;
vect p1, dp1, snorm1;
vect p2, dp2, snorm2;
vect gnorm;
} segment;
static int ntemp, tempstart;
static segment temp[MAXTEMP];
static int npath, pathstart;
static segment path[MAXPATH];
static int trierror;
static float noisemag;
/*
* Describe the template
*
*/
tempbegin()
{
ntemp = 0;
tempstart = 0;
}
tempsegment(p1,dp1,p2,dp2)
vect *p1,*dp1,*p2,*dp2;
{
newsegment(temp,ntemp++,p1,dp1,p2,dp2);
if(ntemp == MAXTEMP) {
fprintf(stderr,"tempsegment: too many template segments\n");
exit(1);
}
}
tempclose()
{
if(tempstart != ntemp) {
if( (temp[tempstart].p1.x == temp[ntemp-1].p2.x) &&
(temp[tempstart].p1.y == temp[ntemp-1].p2.y) ) {
temp[tempstart].prev = ntemp-1;
temp[ntemp-1].next = tempstart;
} else {
temp[tempstart].prev = -1;
temp[ntemp-1].next = -1;
}
tempstart = ntemp;
}
}
/*
* Describe the path
*
*/
pathbegin()
{
npath = 0;
pathstart = 0;
}
pathsegment(p1,dp1,p2,dp2)
vect *p1,*dp1,*p2,*dp2;
{
newsegment(path,npath++,p1,dp1,p2,dp2);
if(npath == MAXPATH) {
fprintf(stderr,"pathsegment: too many path segments\n");
exit(1);
}
}
pathclose()
{
if(pathstart != npath) {
if( (path[pathstart].p1.x == path[npath-1].p2.x) &&
(path[pathstart].p1.y == path[npath-1].p2.y) ) {
path[pathstart].prev = npath-1;
path[npath-1].next = pathstart;
} else {
path[pathstart].prev = -1;
path[npath-1].next = -1;
}
pathstart = npath;
}
}
pathnoise(mag)
float mag;
{
noisemag = mag;
}
static float addnoise(v)
float v;
{
return v+noisemag*(frand()-0.5);
}
static newsegment(seg,nseg,p1,dp1,p2,dp2)
segment seg[];
int nseg;
vect *p1,*dp1,*p2,*dp2;
{
vect slope;
slope.x = p2->x-p1->x;
slope.y = p2->y-p1->y;
slope.z = 0.0;
seg[nseg].p1 = *p1;
seg[nseg].p1.z = 0.0;
seg[nseg].p2 = *p2;
seg[nseg].p2.z = 0.0;
if(dp1) {
seg[nseg].dp1 = *dp1;
seg[nseg].dp1.z = 0.0;
} else
seg[nseg].dp1 = slope;
if(dp2) {
seg[nseg].dp2 = *dp2;
seg[nseg].dp2.z = 0.0;
} else
seg[nseg].dp2 = slope;
seg[nseg].prev = nseg-1;
seg[nseg].next = nseg+1;
}
/*
* Sweep the template along the path.
*
*/
sgiobj *follow()
{
int looptemp, looppath;
int t, p;
vect gvect1, gvect2;
vect svect1, svect2;
float x, y;
int nquads;
sgiobj *obj;
float *temp1, *temp2;
float *t1ptr, *t2ptr, *fptr;
tempclose();
pathclose();
normsegs(temp,ntemp);
normsegs(path,npath);
nquads = ntemp*npath;
obj = newtriobj(2*nquads);
fptr = (float*)obj->data;
temp1 = (float*)mymalloc(2*ntemp*sizeof(float)*PNTLONGS);
temp2 = (float*)mymalloc(2*ntemp*sizeof(float)*PNTLONGS);
for(p=0; p<npath; p++) {
getcornervect(&gvect1,path[p].prev,p);
getcornervect(&gvect2,p,path[p].next);
transtemp(temp,temp1,&path[p].p1,&gvect1,&path[p].snorm1,ntemp);
transtemp(temp,temp2,&path[p].p2,&gvect2,&path[p].snorm2,ntemp);
t1ptr = temp1;
t2ptr = temp2;
for(t=0; t<ntemp; t++) {
bcopy(t1ptr+(0*PNTLONGS),fptr,PNTLONGS*sizeof(float));
fptr += PNTLONGS;
bcopy(t2ptr+(0*PNTLONGS),fptr,PNTLONGS*sizeof(float));
fptr += PNTLONGS;
bcopy(t1ptr+(1*PNTLONGS),fptr,PNTLONGS*sizeof(float));
fptr += PNTLONGS;
bcopy(t2ptr+(1*PNTLONGS),fptr,PNTLONGS*sizeof(float));
fptr += PNTLONGS;
bcopy(t1ptr+(1*PNTLONGS),fptr,PNTLONGS*sizeof(float));
fptr += PNTLONGS;
bcopy(t2ptr+(0*PNTLONGS),fptr,PNTLONGS*sizeof(float));
fptr += PNTLONGS;
t1ptr += 2*PNTLONGS;
t2ptr += 2*PNTLONGS;
}
}
free(temp1);
free(temp2);
return obj;
}
static transtemp(temp,fptr,pos,gvect,gnorm,n)
segment *temp;
float *fptr;
vect *pos, *gvect, *gnorm;
int n;
{
float x, y, z;
float nx, ny, nz;
while(n--) {
x = pos->x+temp->p1.x*gvect->x;
y = pos->y+temp->p1.x*gvect->y;
z = temp->p1.y;
nx = temp->snorm1.x*gnorm->x;
ny = temp->snorm1.x*gnorm->y;
nz = temp->snorm1.y;
fptr[OFFSET_POINT+0] = x;
fptr[OFFSET_POINT+1] = y;
fptr[OFFSET_POINT+2] = z;
fptr[OFFSET_NORMAL+0] = nx;
fptr[OFFSET_NORMAL+1] = ny;
fptr[OFFSET_NORMAL+2] = nz;
fptr[OFFSET_UVS+0] = x;
fptr[OFFSET_UVS+1] = y;
fptr[OFFSET_UVS+2] = z;
fptr += PNTLONGS;
x = pos->x+temp->p2.x*gvect->x;
y = pos->y+temp->p2.x*gvect->y;
z = temp->p2.y;
nx = temp->snorm2.x*gnorm->x;
ny = temp->snorm2.x*gnorm->y;
nz = temp->snorm2.y;
fptr[OFFSET_POINT+0] = x;
fptr[OFFSET_POINT+1] = y;
fptr[OFFSET_POINT+2] = z;
fptr[OFFSET_NORMAL+0] = nx;
fptr[OFFSET_NORMAL+1] = ny;
fptr[OFFSET_NORMAL+2] = nz;
fptr[OFFSET_UVS+0] = x;
fptr[OFFSET_UVS+1] = y;
fptr[OFFSET_UVS+2] = z;
fptr += PNTLONGS;
temp++;
}
}
static getcornervect(cvect,p1,p2)
vect *cvect;
int p1, p2;
{
float dot;
if(p1<0) {
*cvect = path[p2].gnorm;
} else if(p2<0) {
*cvect = path[p1].gnorm;
} else {
vadd(&path[p1].gnorm,&path[p2].gnorm,cvect);
dot = vdot(&path[p1].gnorm,cvect);
vscale(cvect,1.0/dot);
}
}
static normsegs(segs,nsegs)
segment *segs;
int nsegs;
{
int i;
float mag, dx, dy;
if(segs == 0) {
fprintf(stderr,"follow: template or path has no segemets\n");
exit(1);
}
for(i=0; i<nsegs; i++) {
mag = sqrt(segs->dp1.x*segs->dp1.x + segs->dp1.y*segs->dp1.y);
if(mag<EPSILON) {
fprintf(stderr,"follow: bad poop 1\n");
exit(1);
}
segs->snorm1.x = segs->dp1.y/mag;
segs->snorm1.y = -segs->dp1.x/mag;
mag = sqrt(segs->dp2.x*segs->dp2.x + segs->dp2.y*segs->dp2.y);
if(mag<EPSILON) {
fprintf(stderr,"follow: bad poop 2\n");
exit(1);
}
segs->snorm2.x = segs->dp2.y/mag;
segs->snorm2.y = -segs->dp2.x/mag;
dx = segs->p2.x - segs->p1.x;
dy = segs->p2.y - segs->p1.y;
mag = sqrt(dx*dx+dy*dy);
if(mag<EPSILON) {
fprintf(stderr,"follow: bad poop %d %f %f 3\n",i,dx,dy);
exit(1);
}
segs->gnorm.x = dy/mag;
segs->gnorm.y = -dx/mag;
segs->gnorm.z = 0.0;
segs++;
}
}
static float *objfptr;
static sgiobj *faceobj;
static int polyp, outtri, maxtri;
static float facesign, facez;
/*
* triangulation stuff follows
*
*/
static int trifunc(verts)
float *verts[3];
{
float x, y, z;
int i, offset;
float *fptr;
for(i=0; i<3; i++) {
fptr = verts[i];
x = fptr[0];
y = fptr[1];
z = facez;
if(facesign>0.0)
offset = i;
else
offset = 2-i;
putobjvert(objfptr+offset*PNTLONGS,x,y,z);
}
objfptr += 3*PNTLONGS;
outtri++;
}
static putobjvert(fptr,x,y,z)
float *fptr;
float x, y, z;
{
fptr[OFFSET_NORMAL+0] = 0.0;
fptr[OFFSET_NORMAL+1] = 0.0;
fptr[OFFSET_NORMAL+2] = facesign;
fptr[OFFSET_POINT+0] = x;
fptr[OFFSET_POINT+1] = y;
fptr[OFFSET_POINT+2] = z;
fptr[OFFSET_UVS+0] = x;
fptr[OFFSET_UVS+1] = y;
fptr[OFFSET_UVS+2] = z;
}
static void out_bgnpoly()
{
mesh_callback(trifunc);
}
static void out_endpoly()
{
}
static void out_bgntmesh()
{
mesh_bgntmesh();
}
static void out_swaptmesh()
{
mesh_swaptmesh();
}
static void out_vertex(iptr)
int *iptr;
{
mesh_vert(iptr);
}
static void out_endtmesh()
{
mesh_endtmesh();
}
static void out_error(str)
char *str;
{
fprintf(stderr,"triangulate error [%s]\n",str);
trierror = 1;
}
/*
* face support follows
*
*/
sgiobj *getfaces()
{
int nlevels;
int ntri, tottri;
int p, t, added;
int nverts;
float x, y;
TriangulatorObj *tripak;
tempclose();
pathclose();
normsegs(temp,ntemp);
normsegs(path,npath);
/* count levels */
nlevels = 0;
for(t=0; t<ntemp; t++) {
if(temp[t].p1.x == 0.0 || temp[t].p2.x == 0.0)
nlevels++;
}
/* count number of ring segments */
nverts = 0;
p = 0;
while(1) {
while(p<npath) {
if(path[p].prev>p) {
break;
}
p++;
}
if(p == npath)
break;
while(path[p].next>p) {
nverts+=2; /* worst case */
p++;
}
p++;
nverts++;
}
ntri = nverts;
tottri = ntri*nlevels;
maxtri = tottri;
if(tottri==0)
return 0;
faceobj = newtriobj(tottri);
objfptr = (float *)faceobj->data;
outtri = 0;
added = 0;
trierror = 0;
tripak = newTriangulator(out_bgnpoly,out_endpoly,
out_bgntmesh,out_swaptmesh,out_vertex,out_endtmesh,out_error);
for(t=0; t<ntemp; t++) {
if(temp[t].p1.x == 0.0 || temp[t].p2.x == 0.0) {
if(temp[t].p1.x == 0.0) {
facez = temp[t].p1.y;
facesign = -1.0;
} else {
facez = temp[t].p2.y;
facesign = 1.0;
}
p = 0;
in_bgnpoly(tripak,0);
while(1) {
while(p<npath) {
if(path[p].prev>p)
break;
p++;
}
if(p >= npath)
break;
in_bgnloop(tripak,TRI_UNKNOWN);
while(path[p].next>p) {
x = path[p].p1.x;
y = path[p].p1.y;
if(noisemag>0.0)
in_vertex(tripak,addnoise(x),addnoise(y),(int *)(&path[p].p1));
else
in_vertex(tripak,addnoise(x),addnoise(y),(int *)(&path[p].p1));
p++;
added++;
}
x = path[p].p1.x;
y = path[p].p1.y;
if(noisemag>0.0)
in_vertex(tripak,addnoise(x),addnoise(y),(int *)(&path[p].p1));
else
in_vertex(tripak,x,y,(int *)(&path[p].p1));
p++;
added++;
in_endloop(tripak);
}
in_endpoly(tripak);
}
}
freeTriangulator(tripak);
if(trierror)
return 0;
if(outtri>tottri) {
fprintf(stderr,"get face bad poop %d %d\n",outtri,tottri);
}
faceobj->nlongs = outtri*3*PNTLONGS;
return faceobj;
}